package com.lemon.cloud.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.lemon.cloud.admin.mapper.SysMenuMapper;
import com.lemon.cloud.admin.service.SysApplicationService;
import com.lemon.cloud.admin.service.SysMenuService;
import com.lemon.cloud.admin.service.SysRoleService;
import com.lemon.cloud.admin.vo.AppMenuVO;
import com.lemon.cloud.comm.constants.CommonConstants;
import com.lemon.cloud.comm.constants.enums.DelFlagEnum;
import com.lemon.cloud.comm.constants.enums.MenuTypeEnum;
import com.lemon.cloud.comm.model.ResultMsg;
import com.lemon.cloud.comm.po.SysMenu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Autowired
    private SysRoleService roleService;

    @Autowired
    private SysApplicationService applicationService;

    @Override
    public List<SysMenu> getMenuByRoles(Long[] roleIds) {
        if (roleIds == null || roleIds.length == 0) {
            return Lists.newArrayList();
        }
        return baseMapper.getMenuByRoles(roleIds);
    }

    @Override
    public List<Tree<Long>> filterMenu(Set<SysMenu> menuSet, String type, Long parentId, Long appId) {
        List<Tree<Long>> result = Lists.newArrayList();
        List<TreeNode<Long>> collect = menuSet.stream()
                .filter(filterType(type))
                .filter(filterAppId(type,appId))
                .filter(menu -> StrUtil.isNotBlank(menu.getPath())).map(getNodeFunction()).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(collect)) {
            return result;
        }
        if (parentId != null) {
            List<Tree<Long>> build = TreeUtil.build(collect, parentId);
            if (CollectionUtil.isNotEmpty(build)) {
                result.addAll(build);
            }
        } else {
            Set<Long> idList = collect.stream().map(TreeNode::getId).collect(Collectors.toSet());
            Set<Long> parentList = collect.stream().map(TreeNode::getParentId).collect(Collectors.toSet());
            parentList.removeAll(idList);
            for (Long p : parentList) {
                List<Tree<Long>> build = TreeUtil.build(collect, p);
                if (CollectionUtil.isNotEmpty(build)) {
                    result.addAll(build);
                }
            }
        }

        return result;
    }

    /**
     * 过滤
     *
     * @param type
     * @return
     */
    private Predicate<SysMenu> filterType(String type) {
        return sysMenu -> {
            if (StrUtil.isNotEmpty(type)) {
                String typeByDesc = MenuTypeEnum.getTypeByDesc(type);
                return typeByDesc != null && typeByDesc.equals(sysMenu.getType());
            }
            return !MenuTypeEnum.TOP_MENU.getType().equals(sysMenu.getType());
        };
    }

    /**
     * 过滤
     *
     * @param appId
     * @param type
     * @return
     */
    private Predicate<SysMenu> filterAppId(String type,Long appId) {
        return sysMenu -> {
            if (type==null&&appId!=null) {
                return appId.equals(sysMenu.getAppId());
            }
            return true;
        };
    }

    /**
     * 构建树查询 1. 不是懒加载情况，查询全部
     * 2. 是懒加载，根据parentId 查询
     * 3. 父节点为空，则查询ID -1
     *
     * @param lazy
     * @param parent
     * @return
     */
    @Override
    public List<Tree<Long>> treeMenu(boolean lazy, Long parent, Long appId) {
        parent = parent == null ? CommonConstants.MENU_TREE_ROOT_ID : parent;

        //包含应用组织树结构
        if (!lazy) {
            List<TreeNode<Long>> collect = baseMapper
                    .selectList(Wrappers.<SysMenu>lambdaQuery()
                            .eq(SysMenu::getDelFlag, DelFlagEnum.EXIST.getValue())
                            .eq(appId!=null,SysMenu::getAppId, appId)
                            .orderByAsc(SysMenu::getSortOrder)).stream()
                    .map(getNodeFunction()).collect(Collectors.toList());
            return TreeUtil.build(collect, parent);
        }


        List<TreeNode<Long>> collect = baseMapper
                .selectList(Wrappers.<SysMenu>lambdaQuery()
                        .eq(appId!=null,SysMenu::getAppId, appId)
                        .eq(SysMenu::getParentId, parent)
                        .eq(SysMenu::getDelFlag, DelFlagEnum.EXIST.getValue())
                        .orderByAsc(SysMenu::getSortOrder))
                .stream().map(getNodeFunction()).collect(Collectors.toList());

        return TreeUtil.build(collect, parent);
    }


    @Override
    public List<AppMenuVO> findMenuByRoleId(Long roleId) {
        List<AppMenuVO> result = Lists.newArrayList();
        List<SysMenu> menuByRoles = baseMapper.getMenuByRoles(new Long[]{roleId});
        if (CollectionUtil.isEmpty(menuByRoles)){
            return result;
        }
        Map<Long, List<Long>> listMap = menuByRoles.stream().collect(Collectors.groupingBy(SysMenu::getAppId, Collectors.mapping(SysMenu::getId, Collectors.toList())));
        for(Map.Entry<Long, List<Long>> entry : listMap.entrySet()){
            if (CollectionUtil.isNotEmpty(entry.getValue())){
                AppMenuVO appMenuVO = new AppMenuVO();
                appMenuVO.setAppId(entry.getKey());
                appMenuVO.setMenuIdList(entry.getValue());
                result.add(appMenuVO);
            }
        }
        return result;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMsg<Boolean> removeMenuById(Long id) {
        // 查询父节点为当前节点的节点
        List<SysMenu> menuList = this.list(Wrappers.<SysMenu>query().lambda().eq(SysMenu::getParentId, id));

        if (CollectionUtil.isNotEmpty(menuList)) {
            return ResultMsg.resultFail("存在子菜单，无法删除");
        }
        roleService.delRolePermission(id, null);
        return ResultMsg.resultSuccess(this.update(Wrappers.<SysMenu>update().lambda().set(SysMenu::getDelFlag, DelFlagEnum.DELETE.getValue()).eq(SysMenu::getId, id)));
    }

    @Override
    public Boolean updateMenuById(SysMenu sysMenu) {
        return this.updateById(sysMenu);
    }

    private Function<SysMenu, TreeNode<Long>> getNodeFunction() {
        return menu -> {
            TreeNode<Long> node = new TreeNode<>();
            node.setId(menu.getId());
            node.setName(menu.getName());
            node.setParentId(menu.getParentId());
            node.setWeight(menu.getSortOrder());
            // 扩展属性
            Map<String, Object> extra = new HashMap<>();
            extra.put("appId", menu.getAppId());
            extra.put("icon", menu.getIcon());
            extra.put("path", menu.getPath());
            extra.put("type", menu.getType());
            extra.put("permission", menu.getPermission());
            extra.put("label", menu.getName());
            extra.put("sortOrder", menu.getSortOrder());
            extra.put("status", menu.getStatus());
            extra.put("keepAlive", menu.getKeepAlive());
            node.setExtra(extra);
            return node;
        };
    }
}
